`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/04/27 21:16:42
// Design Name: 
// Module Name: test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module test;
//
parameter Tr =14 ;
parameter Tc =12 ;
parameter K = 3;
parameter Tm = 8;
parameter Tn = 4;
//
logic clk;
logic rst;
logic start;
logic done;
logic [15:0] InAddr;
logic [15:0] KernelAddr;
logic [15:0] ReadOutAddr;
logic [15:0] WriteOutAddr;
logic [15:0] InData [0:Tn-1];
logic [15:0] KernelData [0:Tm-1][0:Tn-1];
logic [15:0] ReadOut [0:Tm-1];
logic [15:0] WriteOut [0:Tm-1];
logic we;

logic [15:0] InBuffer[0:Tn-1][0:(Tr+K-1)*(Tc+K-1)-1];
logic [15:0] KernelBuffer[0:Tm-1][0:Tn-1][0:K*K-1];
logic [15:0] OutBuffer[0:Tm-1][0:Tr*Tc-1];
logic [15:0] RefOutBuffer[0:Tm-1][0:Tr-1][0:Tc-1];
initial
begin
begin
    for(int m=0;m<Tm;m++)
        for(int r=0;r<Tr;r++)
            for(int c=0;c<Tc;c++)
                RefOutBuffer[m][r][c]=0;
end
#1000
begin
    for(int kx=0;kx<K;kx++)
        for(int ky=0;ky<K;ky++)
            for(int r=0;r<Tr;r++)
                for(int c=0;c<Tc;c++)
                   for(int m=0;m<Tm;m++)
                       for(int n=0;n<Tn;n++)
                           RefOutBuffer[m][r][c]=RefOutBuffer[m][r][c]+InBuffer[n][(r+kx)*(Tc+K-1)+c+ky]*KernelBuffer[m][n][kx*K+ky];
end
end
//clk
initial 
begin
    clk=0;
    forever begin
        #5 clk=~clk;
    end    
end
//rst
initial begin
    rst=1;
    #20
    rst=0;
end
//start
initial begin
    start=0;
    #50
    start=1;
    #10
    start=0;
end
//InBuffer Initialization
always_ff@(posedge clk,posedge rst)
if(rst)
begin
    for(int i=0;i<(Tr+K-1)*(Tc+K-1);i++)
        for(int n=0;n<Tn;n++)
            InBuffer[n][i]<={$random} % 10;
end
//KernelBuffer
always_ff@(posedge clk,posedge rst)
if(rst)
begin
    for(int m=0;m<Tm;m++)
        for(int n=0;n<Tn;n++)
            for(int i=0;i<K*K;i++)
                KernelBuffer[m][n][i]<={$random} % 20;
end
//OutBuffer
always_ff@(posedge clk,posedge rst)
if(rst)
begin
    for(int m=0;m<Tm;m++)
        for(int i=0;i<Tr*Tc;i++)
             OutBuffer[m][i]<=0;
end
else if(we)
begin
    for(int m=0;m<Tm;m++)
        OutBuffer[m][WriteOutAddr]<=WriteOut[m];
end
//read InBuffer
always_ff@(posedge clk)
begin
   for(int n=0;n<Tn;n++)
        InData[n]<=InBuffer[n][InAddr];
end
//read KernelBuffer
always_ff@(posedge clk)
begin
    for(int m=0;m<Tm;m++)
        for(int n=0;n<Tn;n++)
             KernelData[m][n]<=KernelBuffer[m][n][KernelAddr];
end
//read OutBuffer
always_ff@(posedge clk)
begin
    for(int m=0;m<Tm;m++)
         ReadOut[m]<=OutBuffer[m][ReadOutAddr];
end
//test
logic done_ff1;
always_ff@(posedge clk)
    done_ff1<=done;
//
always_ff@(posedge clk)
if(done_ff1)
begin
    int count=0;
    for(int m=0;m<Tm;m++)
        for(int r=0;r<Tr;r++)
            for(int c=0;c<Tc;c++)
            begin
                $display("%d,%d",RefOutBuffer[m][r][c],OutBuffer[m][r*Tc+c]);
                if(RefOutBuffer[m][r][c]!=OutBuffer[m][r*Tc+c])
                    count+=1;
            end
    $display("count=%d",count);
end

//inst
tiled_conv 
#(
.Tr(Tr),
.Tc(Tc),
.K(K),
.Tn(Tn),
.Tm(Tm)
)
U(.*);
endmodule
